package db

import (
	"bytes"
	"fmt"
	"github.com/lishimeng/go-log"
	"strings"
)

type Column struct {
	ColumnName string
	Field      string
	Type       ColumnType
}

func DdlInsert(table string, columns []string, params []string) (ddl string) {
	const insert = `INSERT INTO %s (%s) values(%s);`
	ddlColumns := strings.Join(columns, ",")
	ddlParams := strings.Join(params, ",")
	ddl = fmt.Sprintf(insert, table, ddlColumns, ddlParams)
	log.Info(ddl)
	return
}

func DdlCreateTable(name string, columns ...Column) string {

	var columnSqlList []string
	columnSqlList = append(columnSqlList, `"id" bigserial NOT NULL PRIMARY KEY,`)
	for _, column := range columns {
		columnTypeSql, exist := GenColumnType(column)
		if !exist {
			panic(fmt.Sprintf("unsupported column type: %v", column))
		}
		colSql := fmt.Sprintf(`"%s" %s ,`, column.ColumnName, columnTypeSql)
		columnSqlList = append(columnSqlList, colSql)
	}
	columnSqlList = append(columnSqlList, `"ctime" timestamp with time zone NOT NULL`)

	var buf = bytes.NewBufferString("\n")
	buf.WriteString("-- --------------------------------------------------\n")
	buf.WriteString(fmt.Sprintf("--  Table Structure for `%s`\n", name))
	buf.WriteString("-- --------------------------------------------------\n")
	buf.WriteString(fmt.Sprintf(`CREATE TABLE IF NOT EXISTS "%s" ( `, name) + "\n")
	for _, item := range columnSqlList {
		buf.WriteString("\t" + item + "\n")
	}
	buf.WriteString(`);` + "\n")
	return buf.String()
}

func ShowTablesQuery() string {
	return "SELECT table_name FROM information_schema.tables WHERE table_type = 'BASE TABLE' AND table_schema NOT IN ('pg_catalog', 'information_schema')"
}

func ShowColumnsQuery(table string) string {
	ddl := `
SELECT column_name--, data_type, is_nullable
FROM information_schema.Columns
where table_schema NOT IN ('pg_catalog', 'information_schema') and table_name = '%s';`
	return fmt.Sprintf(ddl, table)
}

func DdlAddColumn(table string, column Column) string {

	var sql = ""
	columnTypeSql, exist := GenColumnType(column)
	if !exist {
		panic(column.ColumnName)
	}
	sql = fmt.Sprintf(`ALTER TABLE "%s" ADD COLUMN "%s" %s ;`, table, column.ColumnName, columnTypeSql)
	return sql
}

func GenColumnType(pare Column) (string, bool) {
	c, ok := columnNullableTypes[pare.Type]
	return c, ok
}

type ColumnType string

const (
	Int     ColumnType = "int"
	Int64   ColumnType = "int64"
	String  ColumnType = "string"
	Float64 ColumnType = "float64"
	Bool    ColumnType = "bool"
)

var columnTypes = map[ColumnType]string{
	Int:     "integer NOT NULL DEFAULT 0",
	Int64:   "bigint NOT NULL DEFAULT 0",
	String:  "text NOT NULL DEFAULT ''",
	Float64: "double precision NOT NULL DEFAULT 0",
	Bool:    "bool NOT NULL DEFAULT false",
}

var columnNullableTypes = map[ColumnType]string{
	Int:     "integer",
	Int64:   "bigint",
	String:  "text",
	Float64: "double precision",
	Bool:    "bool",
}
